﻿using System.Collections;
using System.Linq;
using System.Collections.Generic;
using Moria.Common.Enum;
using Redbrick.Silverlight.Common;
using System;
using System.Collections.Specialized;
using Redbrick.Silverlight.Serialization;

namespace Moria.Common.Model
{
	public class InventoryCollection : INotifyCollectionChanged, IEnumerable<InventoryItem>
	{

		#region Consts & Settings

		public const int MaxSize = 34;

		#endregion Consts & Settings

		#region Declarations

		List<InventoryItem> _items = new List<InventoryItem>();

		#endregion Declarations

		#region Constructor

		public InventoryCollection()
		{
			this.DebugMethodInfo();
		}
		public InventoryCollection(InventoryItem[] values)
		{
			this.DebugMethodInfo(values);
			this._items.Clear();
			this._items.AddRange(values);
		}

		#endregion Constructor

		#region Methods

		private InventoryItem Get(InventoryLocation location)
		{
			this.DebugMethodInfo(location);
			return this._items.FirstOrDefault(i => i.Location == location);
		}
		public InventoryItem Remove(InventoryLocation location)
		{
			this.DebugMethodInfo(location);
			InventoryItem oldItem = Get(location);
			if (oldItem == null) return null;
			int ndx = this._items.IndexOf(oldItem);
			this._items.Remove(oldItem);
			RaiseCollectionChanged(oldItem, null, ndx);

			return oldItem;
		}
		public InventoryLocation Remove(InventoryItem itm)
		{
			this.DebugMethodInfo(itm);
			int ndx = this._items.IndexOf(itm);
			this._items.Remove(itm);
			RaiseCollectionChanged(itm, null, ndx);

			return itm.Location;
		}
		private InventoryItem Set(InventoryLocation location, InventoryItem value)
		{
			this.DebugMethodInfo(location,value);
			InventoryItem oldVal = Get(location);
			if (value == oldVal) return value;
			if (oldVal != null) Remove(location);
			value.Location = location;
			this._items.Add(value);
			RaiseCollectionChanged(oldVal, value, this._items.Count - 1);
			return value;
		}
		public int Add(InventoryItem value)
		{
			this.DebugMethodInfo(value);
			if (value.Location == InventoryLocation.None)
				value.Location = InventoryLocation.Pack;
			this.Set(value.Location, value);
			return this._items.IndexOf(value);
		}
		private void RaiseCollectionChanged(InventoryItem oldItem, InventoryItem newItem, int ndx)
		{
			if (this.CollectionChanged != null)
			{
				NotifyCollectionChangedAction action = NotifyCollectionChangedAction.Reset;

				if (newItem != null && ndx != -1) action = NotifyCollectionChangedAction.Add;
				else if (newItem != null && oldItem != null) action = NotifyCollectionChangedAction.Replace;
				else if (newItem == null && oldItem != null) action = NotifyCollectionChangedAction.Remove;

				NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(action, newItem, oldItem, ndx);

				this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, ndx));

			}
		}

		public static implicit operator InventoryCollection(InventoryItem[] ary)
		{
			return new InventoryCollection(ary);
		}

		public InventoryItem this[InventoryLocation n]
		{
			get { return this.Get(n); }
			set { this.Set(n, value); }
		}
		public InventoryItem this[int n]
		{
			get { return this._items[n]; }
			set { this._items[n] = value; }
		}
		public int IndexOf(InventoryItem itm)
		{
			this.DebugMethodInfo(itm);
			return this._items.IndexOf(itm);
		}
		public IEnumerator<InventoryItem> GetEnumerator()
		{
			for (int i = 0; i < _items.Count; i++)
			{
				yield return _items[i];
			}
		}
		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		#endregion Methods

		#region Events

		public event NotifyCollectionChangedEventHandler CollectionChanged;

		#endregion Events

		#region Properties

		public int Count { get { return _items.Count; } }

		#endregion Properties
	}

	[Serializer(typeof(InventoryCollection))]
	public class InventoryCollectionSerializer : ISerializeObject
	{
		public object[] Serialize(object target)
		{
			InventoryCollection inventory = target as InventoryCollection;
			if (inventory != null)
			{
				object[] ot = new object[inventory.Count];
				inventory.ForEach((ndx, val) => ot[ndx] = val);
				return ot;
			}
			return null;
		}

		public object Deserialize(object[] data)
		{
			InventoryCollection inventory = new InventoryCollection();
			if (inventory != null)
			{
				data.ForEach((val) => inventory.Add((InventoryItem)val));
				return inventory;
			}
			return null;
		}
	}

}
